package tx.core.graphics;

import java.awt.Image;
import java.util.ArrayList;
import java.util.List;

/**
 * The Animation class manages a series of images (frames) and the amount
 * of time to display each frame.
 * 
 * This class is based on class Animation, by David Brackeen.
 *  
 * @author Guilherme Mauro Germoglio Barbosa - germoglio@gmail.com
 */
public class Animation {

	/**
	 * The frames from the animation. 
	 */
	private List<AnimationFrame> frames;
	
	/**
	 * The current frame index.
	 */
	private int currentFrameIndex;
	
	/**
	 * The current time of the animation.
	 */
	private long animationTime;
	
	/**
	 * The total duration of the animation. 
	 */
	private long totalDuration;
	
	/**
	 * Creates a new, empty animation.
	 */
	public Animation() {
		frames = new ArrayList<AnimationFrame>();
		totalDuration = 0;
		start();
	}
	
	/**
	 * Adds an image to the animation with the specified duration (time
	 * to display the image).
	 * @param image The image to be added.
	 * @param duration Its duration, in milliseconds.
	 */
	public synchronized void addFrame(Image image, long duration) {
		totalDuration += duration;
		frames.add(new AnimationFrame(image, totalDuration));
	}
	
	/**
	 * Starts this animation over from the beginning.
	 */
	public synchronized void start() {
		animationTime = 0;
		currentFrameIndex = 0;
	}
	
	/**
	 * Updates this animation's current image (frame), if necessary.
	 * @param elapsedTime The time passed since the begining of the animation.
	 */
	public synchronized void update(long elapsedTime) {
		if (!frames.isEmpty()) {
			animationTime += elapsedTime;
			
			if (animationTime >= totalDuration) {
				animationTime = animationTime % totalDuration;
				currentFrameIndex = 0;
			}
			
			while (animationTime > getFrame(currentFrameIndex).endTime) {
				currentFrameIndex++;
			}
		}
	}
	
	/**
	 * Gets this Animation's current image. 
	 * @return This Animation's current image. Returns <code>null</code> if this animation
	 * has no images.
	 */
	public synchronized Image getImage() {
		if (frames.isEmpty()) {
			return null;
		} else {
			return getFrame(currentFrameIndex).image;
		}
	}
	
	/**
	 * Returns the frame with the specified index.
	 * @param i The index.
	 * @return The AnimationFrame.
	 */
	private AnimationFrame getFrame(int i) {
		return frames.get(i);
	}
	
	/**
	 * An animation frame. A simple wrapper that holds an image and the amount time it should be displayed. 
	 * @author Guilherme Mauro Germoglio Barbosa - germoglio@gmail.com
	 */
	private class AnimationFrame {
		
		/**
		 * The image.
		 */
		Image image;
		/**
		 * The amount of time it should be displayed (in milliseconds).
		 */
		long endTime;
		
		/**
		 * Creates an AnimationFrame.
		 * @param image The frame.
		 * @param endTime The amount of time it should be displayed (in milliseconds).
		 */
		public AnimationFrame(Image image, long endTime) {
			this.image = image;
			this.endTime = endTime;
		}
	}
}
